////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_VECTOR_2_H__
#define __WN_VECTOR_2_H__

#include "WNCore/inc/WNTypes.h"
#include "WNMath/inc/WNSnapDirection.h"

namespace WNMath {
    class WNPoint2;
    class WNPoint3;
    class WNRay2;
    class WNRay3;
    class WNVector3;
    class WNVector4;

    class WNVector2 {
    public:
        WNVector2();
        explicit WNVector2(WN_FLOAT32 _f);
        explicit WNVector2(const WN_FLOAT32* _f);
        explicit WNVector2(WN_FLOAT32 _x, WN_FLOAT32 _y);

        operator WN_FLOAT32* ();
        operator const WN_FLOAT32* () const;

        WN_FLOAT32& operator () (WN_INT32 _index);
        WN_FLOAT32 operator () (WN_INT32 _index) const;

        WNVector2& operator += (const WNVector2& _vector);
        WNVector2& operator -= (const WNVector2& _vector);
        WNVector2& operator *= (const WNVector2& _vector);
        WNVector2& operator += (WN_FLOAT32 _f);
        WNVector2& operator -= (WN_FLOAT32 _f);
        WNVector2& operator *= (WN_FLOAT32 _f);
        WNVector2& operator /= (WN_FLOAT32 _f);

        WNVector2 operator + () const;
        WNVector2 operator - () const;

        WNVector2 operator + (const WNVector2& _vector) const;
        WNVector2 operator - (const WNVector2& _vector) const;
        WNVector2 operator * (const WNVector2& _vector) const;
        WNVector2 operator + (WN_FLOAT32 _f) const;
        WNVector2 operator - (WN_FLOAT32 _f) const;
        WNVector2 operator * (WN_FLOAT32 _f) const;
        WNVector2 operator / (WN_FLOAT32 _f) const;

        friend WNVector2 operator + (WN_FLOAT32 _f, const WNVector2& _vector);
        friend WNVector2 operator - (WN_FLOAT32 _f, const WNVector2& _vector);
        friend WNVector2 operator * (WN_FLOAT32 _f, const WNVector2& _vector);
        friend WNVector2 operator / (WN_FLOAT32 _f, const WNVector2& _vector);

        WN_BOOL operator == (const WNVector2& _vector) const;
        WN_BOOL operator != (const WNVector2& _vector) const;

        WN_VOID Zero();
        WN_VOID Normalize();
        WN_VOID Truncate(WN_FLOAT32 _length);
        WN_VOID Clamp(const WNVector2& _min, const WNVector2& _max);
        WN_VOID Snap(WNSnapDirection _direction = WN_SNAP_NEAREST);
        WN_VOID Reflect(const WNVector2& _normal);
        WN_VOID Rotate(WN_FLOAT32 _angle);
        WN_VOID Scale(WN_FLOAT32 _scale);
        WN_VOID Scale(WN_FLOAT32 _x, WN_FLOAT32 _y);
        WN_VOID Scale(const WNVector2& _scale);

        WN_FLOAT32 Length() const;
        WN_FLOAT32 LengthSquared() const;

        WN_BOOL IsZero() const;

        WN_VOID Set(const WN_FLOAT32* _f);
        WN_VOID Set(WN_FLOAT32 _x, WN_FLOAT32 _y);

        WNVector2 GetNormalized() const;
        WNVector2 GetTruncated(WN_FLOAT32 _length) const;
        WNVector2 GetClamped(const WNVector2& _min, const WNVector2& _max) const;
        WNVector2 GetSnaped(WNSnapDirection _direction = WN_SNAP_NEAREST) const;
        WNVector2 GetReflected(const WNVector2& _normal) const;
        WNVector2 GetRotated(WN_FLOAT32 _angle) const;
        WNVector2 GetScaled(WN_FLOAT32 _scale) const;
        WNVector2 GetScaled(WN_FLOAT32 _x, WN_FLOAT32 _y) const;
        WNVector2 GetScaled(const WNVector2& _scale) const;

        WNPoint2 ToPoint2() const;
        WNPoint3 ToPoint3() const;
        WNRay2 ToRay2() const;
        WNRay2 ToRay2(const WNPoint2& _location) const;
        WNRay3 ToRay3() const;
        WNRay3 ToRay3(const WNPoint3& _location) const;
        WNVector3 ToVector3() const;
        WNVector4 ToVector4() const;

    public:
        union {
            struct {
                WN_FLOAT32 x;
                WN_FLOAT32 y;
            };

            WN_FLOAT32 raw[2];
        };
    };
}

#endif // __WN_VECTOR_2_H__
